Unity Shader 屏幕后效果

您所在的位置:网站首页 5f-54 030 Unity Shader 屏幕后效果

Unity Shader 屏幕后效果

2023-10-12 14:24| 来源: 网络整理| 查看: 265

Unity内置的雾效需要在每个shader中分别编写,造成了极大的不便。这里利用屏幕后处理产生可单独控制且自由度更高的雾效。

 

屏幕后雾效的本质在于,通过深度纹理重构出每个像素在世界空间中的位置,根据得到的世界坐标计算出雾效系数,最后利用雾效系数与雾的颜色相乘并与原始颜色进行插值运算得出最终效果。

float3 afterFog=f*fogColor+(1-f)*origColor;

上面的插值运算中f代表雾效系数,

它有多种计算方法: 

1.线性运算:

f=(dmax-Abs(z))/dmax-dmin;

其中dmax和dmin分别代表受雾影响的最大和最小距离,z为给定的距离位置(像素位置)

2.指数运算:

f=pow(e,-d*Abs(z));

其中d控制雾的浓度,e为数学常量

3.二次指数:

f=pow(e,-pow(d*z,2));

 

为了更方便的对参数进行控制,需要重构每个像素在世界空间中的位置,常规实现方法如下:

1.构建像素的NDC坐标然后用VP矩阵的逆矩阵反向推导

2.通过向量的基本运算求得

方法1需要在片元着色器中进行矩阵乘法,若想得到性能更优的实现方式,考虑使用方法2。

 

向量的基本运算方式如下:

float4 worldPos=_WorldSpaceCameraPos+linearDepth*interpolatedRay;

_WorldSpaceCameraPos表示摄像机在世界空间中的位置,linearDepth*interpolatedRay是为了求得世界空间下的像素相对于摄像机的偏移量。根据向量的加法,就可以求出该像素在世界空间中的位置。

linearDepth线性深度值可以利用摄像机的深度纹理来求,关键在于求一个插值射线interpolatedRay。

 

分析interpolatedRay的含义可以知道,它主要表示该像素到摄像机的方向向量,可以由顶点着色器的各个顶点输出并插值得到。

基于这一点,可以直接在C#脚本中计算出屏幕四个顶点(左上,左下,右上,右下)的向量,传值给顶点着色器即可,这样避免在Shader中进行繁杂的数学运算。

 

参数控制脚本,同时计算顶点相对于摄像机的方向向量。此脚本挂载在摄像机上:

1 using UnityEngine; 2 3 public class FogWithDepthTexCtrl : ScreenEffectBase 4 { 5 private const string _FrustumCornersRay = "_FrustumCornersRay"; 6 7 private const string _FogDensity = "_FogDensity"; 8 private const string _FogColor = "_FogColor"; 9 private const string _FogUnderStart = "_FogUnderStart"; 10 private const string _FogTopEnd = "_FogTopEnd"; 11 12 private Camera myCamera; 13 public Camera MyCamera 14 { 15 get 16 { 17 if (myCamera == null) 18 myCamera = GetComponent(); 19 return myCamera; 20 } 21 } 22 23 private Transform myCameraTran; 24 public Transform MyCameraTran 25 { 26 get 27 { 28 if (myCameraTran == null) 29 myCameraTran = MyCamera.transform; 30 return myCameraTran; 31 } 32 } 33 34 [Range(0, 3)] 35 public float fogDensity = 1.0f;//控制雾的浓度 36 public Color fogColor = Color.white; 37 public float fogUnderStart = 0.0f;//雾起始高度 38 public float fogTopEnd = 2.0f;//雾结束高度 39 40 private void OnEnable() 41 { 42 MyCamera.depthTextureMode |= DepthTextureMode.Depth; 43 } 44 45 private void OnDisable() 46 { 47 MyCamera.depthTextureMode &= ~DepthTextureMode.Depth; 48 } 49 50 private void OnRenderImage(RenderTexture source, RenderTexture destination) 51 { 52 if (Material != null) 53 { 54 //需要传递的四个角相对于摄像机的方向向量,这里用矩阵的每一行来表示 55 Matrix4x4 frustumCorners = Matrix4x4.identity; 56 57 float fov = MyCamera.fieldOfView; 58 float near = MyCamera.nearClipPlane; 59 float aspect = MyCamera.aspect; 60 61 //计算*裁剪*面三个标准方向 62 float halfHeight = near * Mathf.Tan(fov * .5f * Mathf.Deg2Rad); 63 Vector3 toTop = halfHeight * MyCameraTran.up; 64 Vector3 toRight = halfHeight * MyCameraTran.right * aspect; 65 Vector3 toForward = near * MyCameraTran.forward; 66 67 //用三个标准方向重构四个顶点关于摄像机的向量 68 Vector3 topRight = toForward + toRight + toTop; 69 topRight /= near; 70 71 Vector3 topLeft = toForward - toRight + toTop; 72 topLeft /= near; 73 74 Vector3 bottomRight = toForward + toRight - toTop; 75 bottomRight /= near; 76 77 Vector3 bottomLeft = toForward - toRight - toTop; 78 bottomLeft /= near; 79 80 //用矩阵的每一行来存储这些向量,这里的顺序要与之后解析的顺序对应 81 frustumCorners.SetRow(0, topLeft); 82 frustumCorners.SetRow(1, topRight); 83 frustumCorners.SetRow(2, bottomLeft); 84 frustumCorners.SetRow(3, bottomRight); 85 86 //传递向量矩阵和对应的参数 87 Material.SetMatrix(_FrustumCornersRay, frustumCorners); 88 89 Material.SetFloat(_FogDensity, fogDensity); 90 Material.SetColor(_FogColor, fogColor); 91 Material.SetFloat(_FogUnderStart, fogUnderStart); 92 Material.SetFloat(_FogTopEnd, fogTopEnd); 93 94 Graphics.Blit(source, destination, Material); 95 } 96 else 97 Graphics.Blit(source, destination); 98 } 99 }

 

基类见:

https://www.cnblogs.com/koshio0219/p/11131619.html

 

Shader脚本:

1 Shader "MyUnlit/FogWithDepthTex" 2 { 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 } 7 SubShader 8 { 9 Pass 10 { 11 ZTest Always Cull Off ZWrite Off 12 13 CGPROGRAM 14 #pragma vertex vert 15 #pragma fragment frag 16 17 #include "UnityCG.cginc" 18 19 //对应四个顶点的射线矩阵 20 float4x4 _FrustumCornersRay; 21 22 sampler2D _MainTex; 23 half4 _MainTex_TexelSize; 24 sampler2D _CameraDepthTexture; 25 half _FogDensity; 26 fixed4 _FogColor; 27 float _FogUnderStart; 28 float _FogTopEnd; 29 30 struct appdata 31 { 32 float4 vertex : POSITION; 33 float2 uv : TEXCOORD0; 34 }; 35 36 struct v2f 37 { 38 half4 uv : TEXCOORD0; 39 float4 vertex : SV_POSITION; 40 //顶点着色器输出的插值射线 41 float4 interpolatedRay:TEXCOORD1; 42 }; 43 44 v2f vert (appdata v) 45 { 46 v2f o; 47 o.vertex = UnityObjectToClipPos(v.vertex); 48 o.uv.xy = v.uv; 49 o.uv.zw=v.uv;//zw存深度纹理 50 51 //对插值射线的索引进行解析,判定该顶点是四个角中的哪一个 52 int idx=0; 53 if(v.uv.x>.5f&&v.uv.y>.5f) 54 idx=1; 55 else if(v.uv.x


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3